<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <title>Tutorial Demo</title>
</head>

<style>
    .g6-component-contextmenu {
        position: absolute;
        z-index: 2;
        list-style-type: none;
        background-color: #363b40;
        border-radius: 6px;
        font-size: 14px;
        color: hsla(0, 0%, 100%, .85);
        width: fit-content;
        transition: opacity .2s;
        text-align: center;
        padding: 0px 20px 0px 20px;
        box-shadow: 0 5px 18px 0 rgba(0, 0, 0, 0.6);
        border: 0px;
    }

    .g6-component-contextmenu ul {
        padding-left: 0px;
        margin: 0;
    }

    .g6-component-contextmenu li {
        cursor: pointer;
        list-style-type: none;
        list-style: none;
        margin-left: 0;
        line-height: 38px;
    }

    .g6-component-contextmenu li:hover {
        color: #aaaaaa;
    }
</style>

<body>
    <div id="mountNode"></div>
    <!-- 引入 G6 -->
    <script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.g6-3.7.1/dist/g6.min.js"></script>
    <!-- 4.x and later versions -->
    <!-- <script src="https://gw.alipayobjects.com/os/lib/antv/g6/4.3.11/dist/g6.min.js"></script> -->

    <script>
        console.log(G6.Global.version);

        const contextMenu = new G6.Menu({
            shouldBegin(evt) {
                if (evt.target && evt.target.isCanvas && evt.target.isCanvas()) return true;
                if (evt.item) return true;
                return false;
            },
            getContent(evt) {
                const { item } = evt;
                if (evt.target && evt.target.isCanvas && evt.target.isCanvas()) {
                    return `<ul>
          <li id='show'>Show all Hidden Items</li>
          <li id='collapseAll'>Collapse all Clusters</li>
        </ul>`;
                } else if (!item) return;
                const itemType = item.getType();
                const model = item.getModel();
                if (itemType && model) {
                    if (itemType === 'node') {
                        if (model.level !== 0) {
                            return `<ul>
              <li id='expand'>Expand the Cluster</li>
              <li id='hide'>Hide the Node</li>
            </ul>`;
                        } else {
                            return `<ul>
              <li id='collapse'>Collapse the Cluster</li>
              <li id='neighbor-1'>Find 1-degree Neighbors</li>
              <li id='neighbor-2'>Find 2-degree Neighbors</li>
              <li id='neighbor-3'>Find 3-degree Neighbors</li>
              <li id='hide'>Hide the Node</li>
            </ul>`;
                        }
                    } else {
                        return `<ul>
            <li id='hide'>Hide the Edge</li>
          </ul>`;
                    }
                }
            },
            handleMenuClick: (target, item) => {
                const model = item && item.getModel();
                const liIdStrs = target.id.split('-');
                let mixedGraphData;
                console.log(target, item)
                // switch (liIdStrs[0]) {
                //     case 'hide':
                //         graph.hideItem(item);
                //         hiddenItemIds.push(model.id);
                //         break;
                //     case 'expand':
                //         const newArray = manageExpandCollapseArray(
                //             graph.getNodes().length,
                //             model,
                //             collapseArray,
                //             expandArray,
                //         );
                //         expandArray = newArray.expandArray;
                //         collapseArray = newArray.collapseArray;
                //         mixedGraphData = getMixedGraph(
                //             clusteredData,
                //             data,
                //             nodeMap,
                //             aggregatedNodeMap,
                //             expandArray,
                //             collapseArray,
                //         );
                //         break;
                //     case 'collapse':
                //         const aggregatedNode = aggregatedNodeMap[model.clusterId];
                //         manipulatePosition = { x: aggregatedNode.x, y: aggregatedNode.y };
                //         collapseArray.push(aggregatedNode);
                //         for (let i = 0; i < expandArray.length; i++) {
                //             if (expandArray[i].id === model.clusterId) {
                //                 expandArray.splice(i, 1);
                //                 break;
                //             }
                //         }
                //         mixedGraphData = getMixedGraph(
                //             clusteredData,
                //             data,
                //             nodeMap,
                //             aggregatedNodeMap,
                //             expandArray,
                //             collapseArray,
                //         );
                //         break;
                //     case 'collapseAll':
                //         expandArray = [];
                //         collapseArray = [];
                //         mixedGraphData = getMixedGraph(
                //             clusteredData,
                //             data,
                //             nodeMap,
                //             aggregatedNodeMap,
                //             expandArray,
                //             collapseArray,
                //         );
                //         break;
                //     case 'neighbor':
                //         const expandNeighborSteps = parseInt(liIdStrs[1]);
                //         mixedGraphData = getNeighborMixedGraph(
                //             model,
                //             expandNeighborSteps,
                //             data,
                //             clusteredData,
                //             currentUnproccessedData,
                //             nodeMap,
                //             aggregatedNodeMap,
                //             10,
                //         );
                //         break;
                //     case 'show':
                //         showItems(graph);
                //         break;
                //     default:
                //         break;
                // }
                // if (mixedGraphData) {
                //     cachePositions = cacheNodePositions(graph.getNodes());
                //     currentUnproccessedData = mixedGraphData;
                //     handleRefreshGraph(
                //         graph,
                //         currentUnproccessedData,
                //         CANVAS_WIDTH,
                //         CANVAS_HEIGHT,
                //         largeGraphMode,
                //         true,
                //         false,
                //     );
                // }
            },
            // offsetX and offsetY include the padding of the parent container
            // 需要加上父级容器的 padding-left 16 与自身偏移量 10
            offsetX: 16 + 10,
            // 需要加上父级容器的 padding-top 24 、画布兄弟元素高度、与自身偏移量 10
            offsetY: 0,
            // the types of items that allow the menu show up
            // 在哪些类型的元素上响应
            itemTypes: ['node', 'edge', 'canvas'],
        });


        const initData = {
            // 点集
            nodes: [
                {
                    id: 'node1', // 节点的唯一标识
                    x: 100, // 节点横坐标
                    y: 200, // 节点纵坐标
                    label: '起始点', // 节点文本
                    type: 'rect',
                },
                {
                    id: 'node2',
                    x: 300,
                    y: 200,
                    label: '目标点',
                },
            ],
            // 边集
            edges: [
                // 表示一条从 node1 节点连接到 node2 节点的边
                {
                    source: 'node1', // 起始点 id
                    target: 'node2', // 目标点 id
                    label: '我是连线', // 边的文本
                },
            ],
        };

        const graph = new G6.Graph({
            container: 'mountNode', // 指定挂载容器
            width: 1600, // 图的宽度
            height: 850, // 图的高度
            // fitView: true, // 设置是否将图适配到画布中；
            // fitViewPadding: [20, 40, 50, 20], // 画布上四周的留白宽度。
            animate: true,// 是否启用图的动画。
            layout: {
                // Object，可选，布局的方法及其配置项，默认为 random 布局。
                type: 'radial', // 指定为力导向布局    random-随机  force2-力导向（v4.7之后）  circular-圆环  radial-辐射   concentric-同心圆  dagre-层次  fruchterman、gForce、forceAtlas2、comboForce-力导向   mds-高维数据降维   grid-格子  comboCombined-复合布局
                preventOverlap: true, // 防止节点重叠
                linkDistance: 200, // 指定边距离为100
                // nodeSize: 30        // 节点大小，用于算法中防止节点重叠时的碰撞检测。由于已经在上一节的元素配置中设置了每个节点的 size 属性，则不需要在此设置 nodeSize。
            },
            modes: {
                default: ['drag-canvas', 'zoom-canvas', 'drag-node'], // 允许拖拽画布、放缩画布、拖拽节点
                // default: ['drag-canvas'],
                // edit: []
            },
            defaultNode: {
                size: 30, // 节点大小
                // 节点样式配置
                style: {
                    fill: 'red', // 节点填充色
                    stroke: 'blue', // 节点描边色
                    lineWidth: 3, // 节点描边粗细
                },
                // 节点上的标签文本配置
                labelCfg: {
                    // 节点上的标签文本样式配置
                    style: {
                        fill: '#000', // 节点标签文字颜色
                    },
                },
            },
            defaultEdge: {
                // ...                 // 边的其他配置
                // 边样式配置
                style: {
                    opacity: 1, // 边透明度
                    stroke: 'orange', // 边描边颜色
                },
                // 边上的标签文本配置
                labelCfg: {
                    autoRotate: false, // 边上的标签文本根据边的方向旋转
                },
            },
            nodeStateStyles: {
                // 鼠标 hover 上节点，即 hover 状态为 true 时的样式
                hover: {
                    fill: 'blue',
                },
                // 鼠标点击节点，即 click 状态为 true 时的样式
                click: {
                    stroke: '#000',
                    lineWidth: 3,
                },
            },
            edgeStateStyles: {
                // 鼠标点击边，即 click 状态为 true 时的样式
                click: {
                    stroke: 'red',
                },
            },
            plugins: [contextMenu],
        });



        const main = async () => {
            const response = await fetch(
                'https://gw.alipayobjects.com/os/basement_prod/6cae02ab-4c29-44b2-b1fd-4005688febcb.json',
            );
            const remoteData = await response.json();

            // ...
            console.log(remoteData)
            graph.data(remoteData); // 加载远程数据
            graph.render(); // 渲染

            graph.on('node:mouseenter', (e) => {
                const nodeItem = e.item; // 获取鼠标进入的节点元素对象
                graph.setItemState(nodeItem, 'hover', true); // 设置当前节点的 hover 状态为 true
            });
            graph.on('node:mouseleave', (e) => {
                const nodeItem = e.item; // 获取鼠标离开的节点元素对象
                graph.setItemState(nodeItem, 'hover', false); // 设置当前节点的 hover 状态为 false
            });
            graph.on('node:click', (e) => {
                // 先将所有当前是 click 状态的节点置为非 click 状态
                const clickNodes = graph.findAllByState('node', 'click');
                clickNodes.forEach((cn) => {
                    graph.setItemState(cn, 'click', false);
                });
                const nodeItem = e.item; // 获取被点击的节点元素对象
                graph.setItemState(nodeItem, 'click', true); // 设置当前节点的 click 状态为 true
            });
            // 点击边
            graph.on('edge:click', (e) => {
                console.log(e)
                // 先将所有当前是 click 状态的边置为非 click 状态
                const clickEdges = graph.findAllByState('edge', 'click');
                clickEdges.forEach((ce) => {
                    graph.setItemState(ce, 'click', false);
                });
                const edgeItem = e.item; // 获取被点击的边元素对象
                graph.setItemState(edgeItem, 'click', true); // 设置当前边的 click 状态为 true
            });
        };
        main();

        // setTimeout(() => {
        //     graph.data(initData)
        //     graph.render()
        // }, 5000)
    </script>
</body>

</html>